/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
 * secGear is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <stdio.h>
#include <unistd.h>
// #include <linux/limits.h>
#include "enclave.h"
#include "tstenclave_u.h"
#include "string.h"
// #define DEBUG printf("at: %d %s\n",__LINE__,__FUNCTION__)

#define BUF_LEN 16
const uint32_t *_b;
int a_;
void print_res(uint32_t *token, size_t bs)
{
    _b = token;
    printf("test bs:%lu\n", bs);
}

int main(int argc, char **argv)
{
    // int  retval = 0;
    a_ = argc;
    char *path = PATH;
    // char buf[BUF_LEN];
    cc_enclave_t context = {0};
    cc_enclave_result_t res = CC_FAIL;

    // char real_p[PATH_MAX];
    /* check file exists, if not exist then use absolute path */
    // if (realpath(path, real_p) == NULL) {
    //     if (getcwd(real_p, sizeof(real_p)) == NULL) {
    //         printf("Cannot find enclave.sign.so");
    //         goto end;
    //     }
    //     if (PATH_MAX - strlen(real_p) <= strlen("/enclave.signed.so")) {
    //         printf("Failed to strcat enclave.sign.so path");
    //         goto end;
    //     }
    //     (void)strcat(real_p, "/enclave.signed.so");
    // }

    // res = cc_enclave_create(real_p, AUTO_ENCLAVE_TYPE, 0, SECGEAR_DEBUG_FLAG, NULL, 0, &context);
    res = cc_enclave_create(path, AUTO_ENCLAVE_TYPE, 0, SECGEAR_DEBUG_FLAG, NULL, 0, &context);
    if (res != CC_SUCCESS) {
        printf("host create enclave error\n");
        goto end; 
    }
    printf("host create enclave success\n");

    clock_t start, end;
    double cpu_time_used;
        FILE *file;
        file = fopen(argv[1], "r");
        if (file == NULL) {
        printf("Failed to open input file\n");
        perror("fopen");
        goto destroy_point;
    }
        // char line[1024];
    uint32_t siz_buf[8]={};
    char word_buf[16];
    double timestamp1=0,timestamp2=0,timestamp3=0;
        // while (fgets(line, 1024, file)) {
        while (fscanf(file, "%s", word_buf) != EOF) {
            // char *token;
            // token = strtok(line, ",");
            double st1,st2,st3,st4;
            // while (token != NULL) {
                // printf("%s\n", token);
            st1 = clock();
                insertTST_(&context, word_buf);
                // tstRoot = insertTST(tstRoot, token);
            st2 = clock();
                insertBinary_(&context, word_buf);
                // binaryRoot = insertBinary(binaryRoot, token);
            st3 = clock();
                insertTrie_(&context, word_buf);
                // trieRoot = insertTrie(trieRoot, token);
            st4 = clock();
                timestamp1 += ((double)(st2-st1)) / CLOCKS_PER_SEC;
            timestamp2 += ((double)(st3-st2)) / CLOCKS_PER_SEC;
            timestamp3 += ((double)(st4-st3)) / CLOCKS_PER_SEC;
                // token = strtok(NULL, ",");
            // }
    }
        fclose(file);
        // compress(tstRoot);
    calc_result(&context);
    get_result(&context, siz_buf);

    // size_t tstSize = calculateTSTSize(tstRoot);
    
    // printf("TST size: %zu bytes\n", tstSize);
    // sizeTST_(&context, &siz_buf[0], "ipbmtjybtou");
    printf("TST size: %u bytes\n", siz_buf[0]);
    // printf("TST space used: %d\n", sizeof(TSTNode));
    // size_t binarySize = calculateBinarySize(binaryRoot);
    // printf("Binary tree size: %zu bytes\n", binarySize);
    // sizeBinary_(&context, &siz_buf[1], "ipbmtjybtou");
    printf("Binary tree size: %u bytes\n", siz_buf[1]);

    // size_t trieSize = calculateTrieSize(trieRoot);
    // printf("Trie size: %zu bytes\n", trieSize);
    // sizeTrie_(&context, &siz_buf[2], "ipbmtjybtou");
    printf("Trie size: %u bytes\n", siz_buf[2]);
    printf("test: %u\n", siz_buf[3]);
    // printf("Binary space used: %d\n", sizeof(BinaryNode));
    // printf("Trie space used: %d\n", sizeof(TrieNode));
    printf("done\n");
    // // the sapce is smaller than trie and a little bit large than bianry

    // TSTNode *result_tst = searchTST(tstRoot, "jyjtkrexlan");

    start = clock();
    int result_tst=0;
    searchTST_(&context, &result_tst, "ipbmtjybtou");
    end = clock();
    size_t size_tst=0;
    sizeTST_(&context, &size_tst, "ipbmtjybtou");
    // printf("TST size: %lu bytes\n", size_tst);
    // printf("TST size: %lu bytes\n", result_tst);
    if (result_tst) {
        printf("it exists in the TST\n");
    }
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC ;
    printf("TST insert and search time: %f\n", timestamp1+cpu_time_used);
    // BinaryNode *result_binary = searchBinary(binaryRoot, "jyjtkrexlan");
    int result_binary=0;
    size_t size_binary=0;
    sizeBinary_(&context, &size_binary, "ipbmtjybtou");
    // printf("Binary tree size: %lu bytes\n", size_binary);
    start = clock();
    searchBinary_(&context, &result_binary, "ipbmtjybtou");
    // printf("$%d$\n", result_binary);
    end = clock();
    //printf("Binary tree size: %lu bytes\n", result_binary);
    if (result_binary) {
        printf("it exists in the Binary_Tree\n");
    }
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
    printf("Binary insert and search time: %f\n", timestamp2+cpu_time_used);

    // TrieNode *result_trie1 = searchTrie(trieRoot,"jyjtkrexlan");
    int result_trie1=0;
    size_t size_trie=0;
    sizeTrie_(&context, &size_trie, "ipbmtjybtou");
    // printf("Trie size: %lu bytes\n", size_trie);
    start = clock();
    searchTrie_(&context, &result_trie1, "ipbmtjybtou");
    end = clock();
    // printf("Trie size: %lu bytes\n", result_trie1);
    // TrieNode *result_trie2 = searchTrie(trieRoot,"vhsmhvohyinh");
    // TrieNode *result_trie3 = searchTrie(trieRoot,"kelfmiybcj");
    if (result_trie1) {
        printf("it exists in the Trie\n");
    }
    cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
    printf("Trie insert and search time: %f\n", timestamp3+cpu_time_used);

    size_t size_test=0;
    sizeTest_(&context, &size_test, "ipbmtjybtou");
    // printf("test size: %lu bytes\n", size_trie);
/*
    // if (res != CC_SUCCESS || retval != (int)CC_SUCCESS) {
    //     printf("Ecall enclave error\n");
    // } else {
    //     printf("enclave say:%s\n", buf);
    // }
    
*/

    destroy_point:
    res = cc_enclave_destroy(&context);
    if(res != CC_SUCCESS) {
        printf("host destroy enclave error\n");
    } else {
        printf("host destroy enclave success\n");
    }
end:
    return res;
}

